<?php
/*
 * @Description    : 微信小程序
 * @Author         : QianLong
 * @Date           : 2022-07-18 10:55:08
 * @LastEditors    : QianLong
 * @LastEditTime   : 2024-05-10 17:39:19
 */

declare(strict_types=1);

namespace App\Controller;

use App\Constants\Status;
use App\Exception\ApiException;
use App\Job\SignFailAddJob;
use Yurun\Util\HttpRequest;
use Qianlong\Validate\Validate;

class MpMiniAppController extends AbstractController
{
  public $maInfo = [];
  public function init($param){
    if (empty($param['ma_id'])) {
      throw new ApiException(-1, 'ma_id 不能为空');
    }
    $this->maInfo = $this->redisCache->getMxAppInfo($param['ma_id']);
  }
  public function login()
  {
    $validate = new Validate();
    $validate->addColumn('ma_id')->required();
    $validate->addColumn('code')->required();
    $validate->addColumn('iv')->required();
    $validate->addColumn('encryptedData')->required();
    if ($validate && !$this->validate($validate)) {
      throw new ApiException(Status::CODE_BAD_REQUEST, $validate->getError()->__toString());
    }
    unset($validate);
    $param = $this->request->all();
    $this->init($param);
    $commonService = new \App\Service\Common;
    $newSign2 = $commonService->generateSignature($param, $this->maInfo['server_secret']);
    if ($param['sign'] != $newSign2['sign']) {
      $logData['url'] = $this->request->fullUrl();
      $logData['remoteIp'] = $this->dataResource->getClientIp($this->request);
      $logData['user_sign'] = $param['sign'];
      $logData['uid'] = $this->maInfo['uid'];
      $logData['server_sign'] = $newSign2['sign'];
      $logData['server_query'] = $newSign2['query'];
      queue_push(new SignFailAddJob($logData));
      return $this->response->json(Status::CODE_FAIL, 'sign签名校验失败');
    }
    unset($newSign, $newSign2);
    $url = "https://api.weixin.qq.com/sns/jscode2session";
    $params = [
      'appid' => $this->maInfo['app_id'],
      'secret' => $this->maInfo['app_secret'],
      'js_code' => $param['code'],
      'grant_type' => 'authorization_code'
    ];
    $http = new HttpRequest;
    $response = $http->get($url . '?' . http_build_query($params));
    $result = json_decode($response->body(), true);
    if (!isset($result['session_key']) || empty($result['session_key'])) {
      throw new ApiException(-1, '登录失败，请重试 EG:'.json_encode($result, JSON_UNESCAPED_UNICODE));
    }
    $userInfo = $this->decryptData($result['session_key'], $param['encryptedData'], $param['iv']);
    if ($userInfo === false) {
      throw new ApiException(-1, '登录失败，请重试');
    }
    $userInfo = json_decode($userInfo, true);
    return $this->response->json(Status::CODE_OK, 'success', $userInfo);
  }
  public function getUnLimitedQrcode()
  {
    $validate = new Validate();
    $validate->addColumn('ma_id')->required();
    $validate->addColumn('scene')->required();
    if ($validate && !$this->validate($validate)) {
      throw new ApiException(Status::CODE_BAD_REQUEST, $validate->getError()->__toString());
    }
    unset($validate);
    $param = $this->request->all();
    $this->init($param);
    $commonService = new \App\Service\Common;
    $newSign2 = $commonService->generateSignature($param, $this->maInfo['server_secret']);
    if ($param['sign'] != $newSign2['sign']) {
      $logData['url'] = $this->request->fullUrl();
      $logData['remoteIp'] = $this->dataResource->getClientIp($this->request);
      $logData['user_sign'] = $param['sign'];
      $logData['uid'] = $this->maInfo['uid'];
      $logData['server_sign'] = $newSign2['sign'];
      $logData['server_query'] = $newSign2['query'];
      queue_push(new SignFailAddJob($logData));
      return $this->response->json(Status::CODE_FAIL, 'sign签名校验失败');
    }
    $accessToken = $this->redisCache->getWxAppAccessToken($this->maInfo['app_id'], $this->maInfo['app_secret']);
    $url = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=" . $accessToken;
    $params['scene'] = urldecode($param['scene']);
    if (isset($param['page'])) {
      $params['page'] = $param['page'];
    }
    if (isset($param['check_path'])) {
      $params['check_path'] = $param['check_path'];
    }
    if (isset($param['env_version'])) {
      $params['env_version'] = $param['env_version'];
    }
    if (isset($param['width'])) {
      $params['width'] = $param['width'];
    }
    if (isset($param['auto_color'])) {
      $params['auto_color'] = $param['auto_color'];
    }
    if (isset($param['is_hyaline'])) {
      $params['is_hyaline'] = $param['is_hyaline'];
    }
    if (isset($param['line_color'])) {
      $params['line_color'] = urldecode($param['line_color']);
    }
    $http = new HttpRequest;
    $response = $http->post($url, $params, 'json');
    $result = $response->body();
    $isSuccess = json_decode($result, true);
    if ($isSuccess != null) {
      throw new ApiException(-1, $isSuccess['errmsg']);
    };
    return $this->response->json(200, 'success', base64_encode($response->body()));
  }
  public function getUrlLink()
  {
    $validate = new Validate();
    $validate->addColumn('ma_id')->required();
    if ($validate && !$this->validate($validate)) {
      throw new ApiException(Status::CODE_BAD_REQUEST, $validate->getError()->__toString());
    }
    unset($validate);
    $param = $this->request->all();
    $this->init($param);
    $commonService = new \App\Service\Common;
    $newSign2 = $commonService->generateSignature($param, $this->maInfo['server_secret']);
    if ($param['sign'] != $newSign2['sign']) {
      $logData['url'] = $this->request->fullUrl();
      $logData['remoteIp'] = $this->dataResource->getClientIp($this->request);
      $logData['user_sign'] = $param['sign'];
      $logData['uid'] = $this->maInfo['uid'];
      $logData['server_sign'] = $newSign2['sign'];
      $logData['server_query'] = $newSign2['query'];
      queue_push(new SignFailAddJob($logData));
      return $this->response->json(Status::CODE_FAIL, 'sign签名校验失败');
    }
    $accessToken = $this->redisCache->getWxAppAccessToken($this->maInfo['app_id'], $this->maInfo['app_secret']);
    $url = "https://api.weixin.qq.com/wxa/generate_urllink?access_token=" . $accessToken;
    if (isset($param['path'])) {
      $params['path'] = $param['path'];
    }
    if (isset($param['query'])) {
      $params['query'] = urldecode($param['query']);
    }
    if (isset($param['env_version'])) {
      $params['env_version'] = $param['env_version'];
    }
    if (isset($param['expire_type'])) {
      $params['expire_type'] = $param['expire_type'];
    }
    if (isset($param['auto_color'])) {
      $params['auto_color'] = $param['auto_color'];
    }
    if (isset($param['expire_time'])) {
      $params['expire_time'] = $param['expire_time'];
    }
    if (isset($param['expire_interval'])) {
      $params['expire_interval'] = $param['expire_interval'];
    }
    $http = new HttpRequest;
    $response = $http->post($url, $params, 'json');
    $result = $response->body();
    $isSuccess = json_decode($result, true);
    if ($isSuccess['errcode'] != 0) {
      throw new ApiException(-1, $isSuccess['errmsg']);
    }
    $return['url_link'] = $isSuccess['url_link'];
    return $this->response->json(200, 'success', $return);
  }
  public function getAccessToken()
  {
    $validate = new Validate();
    $validate->addColumn('ma_id')->required()->notEmpty();
    if ($validate && !$this->validate($validate)) {
      throw new ApiException(Status::CODE_BAD_REQUEST, $validate->getError()->__toString());
    }
    unset($validate);
    $param = $this->request->all();
    $this->init($param);
    $commonService = new \App\Service\Common;
    $newSign2 = $commonService->generateSignature($param, $this->maInfo['server_secret']);
    if ($param['sign'] != $newSign2['sign']) {
      $logData['url'] = $this->request->fullUrl();
      $logData['remoteIp'] = $this->dataResource->getClientIp($this->request);
      $logData['user_sign'] = $param['sign'];
      $logData['uid'] = $this->maInfo['uid'];
      $logData['server_sign'] = $newSign2['sign'];
      $logData['server_query'] = $newSign2['query'];
      queue_push(new SignFailAddJob($logData));
      return $this->response->json(Status::CODE_FAIL, 'sign签名校验失败');
    }
    $accessToken = $this->redisCache->getWxAppAccessToken($this->maInfo['app_id'], $this->maInfo['app_secret']);
    return $this->response->json(200, 'success', $accessToken);
  }
  private function decryptData($sessionKey, $encryptedData, $iv)
  {
    $aesKey = base64_decode($sessionKey);
    $aesIV = base64_decode($iv);
    $aesCipher = base64_decode($encryptedData);

    $result = openssl_decrypt($aesCipher, "AES-128-CBC", $aesKey, 1, $aesIV);

    $dataObj = json_decode($result);
    if ($dataObj  == NULL) {
      return false;
    }
    if ($dataObj->watermark->appid != $this->maInfo['app_id']) {
      return false;
    }
    return $result;
  }
}
